﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Reflection;
using ThreeByte.ActiveDeck.Service;
using ThreeByte.ActiveDeck.Data.UserResponse;
using System.ComponentModel;
using ThreeByte.ActiveDeck.Content;
using System.Windows.Media.Imaging;
using ThreeByte.ActiveDeck.AddIn.Content.Controls;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using log4net;

namespace ThreeByte.ActiveDeck.Config
{
    public class PageConfig : INotifyPropertyChanged
    {
        protected static readonly XNamespace ns = ServiceConfiguration.NAMESPACE;
        private static Dictionary<PowerPoint.Presentation, int> scopeInstance = new Dictionary<PowerPoint.Presentation, int>();
        private static readonly ILog log = LogManager.GetLogger(typeof(PageConfig));
        
        private static int ScopedInstance {
            get {
                PowerPoint.Presentation currentPresentation = Globals.ThisAddIn.Application.ActivePresentation;
                if(!(scopeInstance.ContainsKey(currentPresentation))) {
                    scopeInstance[currentPresentation] = 0;
                }
                return scopeInstance[currentPresentation];
            }
            set {
                PowerPoint.Presentation currentPresentation = Globals.ThisAddIn.Application.ActivePresentation;
                if(!(scopeInstance.ContainsKey(currentPresentation))) {
                    scopeInstance[currentPresentation] = 0;
                }
                scopeInstance[currentPresentation] = value;
            }
        }

        public static void ClearPageCache(PowerPoint.Presentation pres) {
            if(scopeInstance.ContainsKey(pres)) {
                scopeInstance.Remove(pres);
            }
        }

        #region Public Properties
        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string propertyName) {
            if(PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public SlideConfig ParentSlideConfig { get; set; }
        public int PageId { get; private set; }

        private string _name;
        public string Name {
            get {
                return _name;
            }
            set {
                _name = value;
                NotifyPropertyChanged("Name");
            }
        }

        private GraphicResource _background;
        public GraphicResource Background {
            get {
                return _background;
            }
            set {
                _background = value;
                NotifyPropertyChanged("Background");
            }
        }

        public TransitionType _transition = TransitionType.Default;
        public TransitionType Transition {
            get {
                return _transition;
            }
            set {
                _transition = value;
                NotifyPropertyChanged("Transition");
            }
        }

        public NavigationAction _navigationAction = new NavigationAction();
        public NavigationAction NavigationAction {
            get {
                return _navigationAction;
            }
            private set {
                _navigationAction = value;
                NotifyPropertyChanged("NavigationAction");
            }
        }

        private Orientation _layoutOrientation = Orientation.LandscapeLeft;
        public Orientation LayoutOrientation {
            get {
                return _layoutOrientation;
            }
            set {
                _layoutOrientation = value;
                NotifyPropertyChanged("LayoutOrientation");
            }
        }

        private bool _showStatusBar = true;
        public bool ShowStatusBar {
            get {
                return _showStatusBar;
            }
            set {
                _showStatusBar = value;
                NotifyPropertyChanged("ShowStatusBar");
            }
        }

        private bool _trackNavigation = true;
        public bool TrackNavigation {
            get {
                return _trackNavigation;
            }
            set {
                _trackNavigation = value;
                NotifyPropertyChanged("TrackNavigation");
            }
        }

        #endregion

        protected PageConfig() {
            PageId = ++(ScopedInstance);
            Name = string.Format("Page_{0}", PageId);
        }

        protected PageConfig(XElement node, Dictionary<Guid, GraphicResource> resources) {
            PageId = int.Parse(node.Attribute("ID").Value);
            //Update the instance so we don't reuse this pageId
            ScopedInstance = Math.Max(ScopedInstance, PageId);

            if(node.Attribute("Name") != null) {
                Name = node.Attribute("Name").Value;
            } else {
                Name = string.Format("Page_{0}", PageId);
            }
            if(node.Attribute("Orientation") != null) {
                LayoutOrientation = (Orientation)(Enum.Parse(typeof(Orientation), node.Attribute("Orientation").Value));
            }
            if(node.Attribute("StatusBar") != null) {
                ShowStatusBar = bool.Parse(node.Attribute("StatusBar").Value);
            }
            if(node.Attribute("TrackNavigation") != null) {
                TrackNavigation = bool.Parse(node.Attribute("TrackNavigation").Value);
            }

            if(node.Attribute("Transition") != null) {
                Transition = TransitionType.Parse(node.Attribute("Transition").Value);
            }

            if(node.Attribute("Background") != null) {
                //Parse the Background ID and grab the resource
                Guid resId = Guid.Parse(node.Attribute("Background").Value);
                if(!resources.ContainsKey(resId)) {
                    log.ErrorFormat("The presentaiton does not contain a background resource: {0}", resId);
                }
                Background = resources[resId];
            }

            XElement navNode = node.Element(ns + "NavigationAction");
            if(navNode != null) {
                NavigationAction = NavigationAction.FromXml(navNode.Element(ns + "Action"));
            }
        }

        public virtual void Refresh() {
            //Refresh the slide config (preview) based on the current parameters
        }

        public virtual XElement ToXml() {
            XElement node = new XElement(ns + "Page");
            node.Add(new XAttribute("ID", PageId));
            if(Name != null) {
                node.Add(new XAttribute("Name", Name));
            }
            node.Add(new XAttribute("Type", this.GetType()));
            node.Add(new XAttribute("Orientation", LayoutOrientation));
            if(!ShowStatusBar) {
                node.Add(new XAttribute("StatusBar", ShowStatusBar));
            }
            node.Add(new XAttribute("Transition", Transition));
            if(Background != null) {
                node.Add(new XAttribute("Background", Background.ID));
            }
            if(NavigationAction != null) {
                node.Add(new XElement(ns + "NavigationAction", NavigationAction.ToXml()));
            }
            if(!TrackNavigation) {
                node.Add(new XAttribute("TrackNavigation", TrackNavigation));
            }
            return node;
        }

        //refactor this type to actually be determined by the object class
        public virtual XElement GetPresentationXml(string type) {

            XElement pageNode = new XElement(ns + "Page", new XAttribute("ID", PageId),
                                                        new XAttribute("Type", type),
                                                        new XAttribute("Orientation", LayoutOrientation),
                                                        new XAttribute("StatusBar", ShowStatusBar),
                                                        new XAttribute("Transition", Transition));
            if(!TrackNavigation) {
                pageNode.Add(new XAttribute("TrackNavigation", TrackNavigation));
            }

            return pageNode;
        }

        /// <summary>
        /// Handles the reflection of instantiating any derived class types
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public static PageConfig FromXml(XElement node, Dictionary<Guid, GraphicResource> resources) {

            Type newModuleType = Type.GetType(node.Attribute("Type").Value, true);
            ConstructorInfo ci = newModuleType.GetConstructor(new Type[] { typeof(XElement), typeof(Dictionary<Guid, GraphicResource>) });
            PageConfig newSlideConfig = (PageConfig)ci.Invoke(new object[] { node, resources });

            return newSlideConfig;
        }

        public static PageConfig NewDefaultPage() {
            return new UserSlideConfig();  //This default type might change
        }

        public virtual List<GraphicResource> GetPersistentGraphicResources() {
            return new List<GraphicResource>();
        }

        public virtual XElement GetReportContext(AggregateUserData userData) {
            return userData.ToXml();
        }
    }


}
